<?php

class QAR extends Extension
{
    protected $queryString;

    /**
     * @return QDb
     */
    public function Select($cols)
    {
        if(is_array($cols))
        {
            $cols = join(",", $cols);
        }

        $this->queryString = "SELECT {$cols} ";

        return $this;
    }

    /**
     * @return QDb
     */
    public function From($table, $as = '')
    {
        $this->queryString .= "FROM {$table} ";

        if(!empty($as))
        {
            $this->queryString .= "AS {$as}";
        }

        return $this;
    }

    /**
     * @return QDb
     */
    public function Insert($table, $data)
    {
        $this->queryString .= "INSERT INTO {$table} ";

        $this->queryString .= "(" . join(",", array_keys($data)) . ") ";
        $this->queryString .= "VALUES ";
        $this->queryString .= "(" . join(",", array_values($data)) . ") ";

        return $this;
    }

    /**
     * @return QDb
     */
    public function Update($table, $data)
    {
        $this->queryString .= "UPDATE {$table} SET ";

        foreach ((array)$data as $key=>$val)
        {
            $arr[] = "$key=$val";
        }

        $this->queryString .= join(",", array_values($arr)) . " ";

        return $this;
    }

    /**
     * @return QDb
     */
    public function Delete($cols = array())
    {
        $this->queryString .= "DELETE ";

        $this->queryString .= join(",", $cols) . " ";

        return $this;
    }

    /**
     * @return QDb
     */
    public function Where($cond)
    {
        $this->queryString .= "WHERE {$cond} ";

        return $this;
    }

    /**
     * @return QDb
     */
    public function Limit($rows)
    {
        $this->queryString .= "LIMIT {$rows} ";

        return $this;
    }

    /**
     * @return QDb
     */
    public function OrderBy($cols, $dir = 'ASC')
    {
        if (is_array($cols))
        {
            $arr = array();

            foreach ($cols as $key=>$val)
            {
                $ord = strtoupper($key);

                if($ord != 'ASC' && $ord != 'DESC')
                {
                    $ord = $dir;
                }

                $arr[] = "{$val} $ord";
            }

            $this->queryString .= "ORDER BY " . join(",", $arr) . " ";
        }
        else
        {
            $this->queryString .= "ORDER BY {$cols} {$dir} ";
        }

        return $this;
    }
}

class QDb extends QAR
{
    public $Driver = "";
    public $Hostname = "";
    public $Port = "";
    public $Username = "";
    public $Password = "";
    public $Database = "";
    public $Encoding = "";
    public $Connection;
    public $Parameters = array();
    public $Cache = null;

    private static $connObject;

    function __construct()
    {

    }

    private function Init()
    {
        $this->Driver = $this->Config->driver;
        $this->Hostname = $this->Config->hostname;
        $this->Port = $this->Config->port;
        $this->Username = $this->Config->username;
        $this->Password = $this->Config->password;
        $this->Database = $this->Config->database;

        define("USE_PDO", class_exists(PDO));

        if (USE_PDO)
        {
            try
            {
                $this->Open();
            }
            catch (PDOException $e)
            {
                throw new QException("PDO Exception: " . $e->getMessage());
            }
        }
        else
        {
            throw new QException("No PDO extension installed");
        }
    }

    public function SetVar($name, $val)
    {
        $this->Parameters[":{$name}"] = $val;

        return true;
    }

    public function GetVar($name)
    {
        return $this->Parameters[":{$name}"];
    }

    public function ClearVars()
    {
        $this->Parameters = array();
    }

    /**
     * @return QDb
     */
    public function Open()
    {
        if(!empty ($this->Driver))
        {
            $dsn = "{$this->Driver}:";
            $dsn .= $this->Port ? "port={$this->Port};" : "";
            $dsn .= $this->Hostname ? "host={$this->Hostname};" : "";
            $dsn .= $this->Database ? "dbname={$this->Database};" : "";
            self::$connObject = new PDO($dsn, $this->Username, $this->Password);
        }

        return $this;
    }

    //- Punblic Methods -

    /**
     * @return mixed
     */
    public function Query($sql = '', $vars = array())
    {
        // We need singleton object otherwise we have big overhead
        if (!(bool)self::$connObject)
        {
            $this->Init();
        }

        $sql = empty($sql) ? $this->queryString : $sql;

        if($vars)
        {
            $params = $vars;
        }
        else
        {
            $params = $this->Parameters;
        }

        $stmt = self::$connObject->prepare($sql);
        $stmt->execute($params);

        $result = $stmt->errorInfo();

        if ($result[1] > 0)
        {
            throw new QException($result[2]);
        }

        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    public function QueryScalar($sql = "", $vars = array())
    {
        // We need singleton object otherwise we have big overhead
        if (!(bool)self::$connObject)
        {
            $this->Init();
        }

        $sql = (empty ($sql)) ? $this->queryString : $sql;

        if($vars)
        {
            $params = $vars;
        }
        else
        {
            $params = $this->Parameters;
        }

        $stmt = self::$connObject->prepare($sql);
        $stmt->execute($params);

        $result = $stmt->errorInfo();

        if ($result[1] > 0)
        {
            throw new QException($result[2]);
        }

        return $stmt->fetch(PDO::FETCH_ASSOC);
    }

    /**
     * @return int
     */
    public function LastID()
    {
        return self::$connObject->lastInsertId();
    }

    public function Cache($timeout)
    {
        $this->Cache = (int)$timeout;

        return $this;
    }
}


